package com.archgeek.java.udp.v2listen;

import com.archgeek.java.udp.MessageCreator;

import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * 相当与客户端,搜索方
 *
 * @author pizhihui
 * @date 2023-03-03
 */
public class UDPSearcherV2 {

    private static final int LISTEN_PORT = 30000;

    public static void main(String[] args) throws InterruptedException, IOException {


        Listener listener = listen();
        sendBraodcast();

        System.in.read();

        List<Device> devicesAndClose = listener.getDevicesAndClose();
        for (Device device : devicesAndClose) {
            System.out.println("device: " + device);
        }
        System.out.println("UDPSearchV2 finished!!!");

    }

    private static Listener listen() throws InterruptedException {
        System.out.println("UDPSearchV2 start listen....");
        CountDownLatch countDownLatch = new CountDownLatch(1);
        Listener listener = new Listener(LISTEN_PORT, countDownLatch);
        listener.start();
        countDownLatch.await();
        return listener;
    }

    private static void sendBraodcast() throws IOException {
        System.out.println("UDPSearcher sendBraodcast Started");

        DatagramSocket ds = null;
        // 监听的 20000 端口
        ds = new DatagramSocket();

        // ByteBuffer.allocate()

        // 发送数据
        String sendData = MessageCreator.buildWithPort(LISTEN_PORT);
        byte[] sendDataByte = sendData.getBytes();
        DatagramPacket requestPacket = new DatagramPacket(sendDataByte, sendDataByte.length);
        // 广播地址
        requestPacket.setAddress(InetAddress.getByName("255.255.255.255"));
        requestPacket.setPort(20000);

        System.out.println("UDPSearcher sendBraodcast.....");
        ds.send(requestPacket);
        ds.close();

        System.out.println("UDPSearcher sendBraodcast Finished!");
    }

    private static class Device {
        int port;
        String ip;
        String sn;


        public Device(int port, String ip, String sn) {
            this.port = port;
            this.ip = ip;
            this.sn = sn;
        }

        @Override
        public String toString() {
            return "Device{" +
                    "port=" + port +
                    ", ip='" + ip + '\'' +
                    ", sn='" + sn + '\'' +
                    '}';
        }
    }

    private static class Listener extends Thread {

        private final int listenPort;
        private final CountDownLatch countDownLatch;
        private final List<Device> devices = new ArrayList<>();

        private boolean done = false;

        private DatagramSocket ds = null;

        public Listener(int port, CountDownLatch countDownLatch) {
            this.listenPort = port;
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            super.run();

            countDownLatch.countDown();
            try {
                // 监听回送端口
                ds = new DatagramSocket(listenPort);

                while (!done) {
                    // 接收服务端返回的数据
                    final byte[] buf = new byte[512];
                    DatagramPacket receivePack = new DatagramPacket(buf, buf.length);
                    // 接收消息
                    System.out.println("UDPSearcher waiting msg......");
                    ds.receive(receivePack);
                    System.out.println("UDPSearcher received msg......receivePack=" + receivePack);

                    String ip = receivePack.getAddress().getHostAddress();
                    int port = receivePack.getPort();
                    int dataLen = receivePack.getLength();
                    String data = new String(receivePack.getData(), 0, dataLen);
                    System.out.println("UDPSearcher receive from ip: " + ip + ",port:" + port + ",data:" + data);

                    String sn = MessageCreator.parseSn(data);
                    if (null != sn) {
                        Device device = new Device(port, ip, sn);
                        devices.add(device);
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                close();
            }

            System.out.println("UDPSearchV2 listerner finished!!!");

        }

        private void close() {
            if (ds != null) {
                ds.close();
            }
        }

        List<Device> getDevicesAndClose() {
            done = true;
            close();
            return devices;
        }

    }

}
